
	/************************************************************************************************

		@API
		Factory: jsl.Date

		Factories:
			d			Date							(date*)
			d			fromLString				(s, fid*)
			d			now								()

		Static:
			obj		format						(fid, pattern*)
			b			isDate						(s, fid*)

		Base:
			d			date							(date*)
			d			month							(month*)
			d			year							(year*)

			d			hours							(hours*)
			d			minutes						(minutes*)
			d			seconds						(seconds*)
			d			milliseconds			(milliseconds*)

		Locales:
			d			locale						(id*)

		Format:
			d			format						(fid*)
			s			toLString					(fid*)

		TimeZone:
			b			useDst						()
			b			isInDst						()
			d			dstStart					()
			d			dstEnd						()
			obj		timeZone					(dst*)

		Movement:
			d			move							(units, clone*)
			d			toFirstDayOfWeek	(clone*)
			d			toLastDayOfWeek		(clone*)
			d			toFirstDayOfMonth	(clone*)
			d			toLastDayOfMonth	(clone*)
			d			toFirstDayOfYear	(clone*)
			d			toLastDayOfYear		(clone*)

		Info:
			b			isInLeapYear			()
			b			between						(date1, date2)
			n			distance					(date, unit*)

			n			daysOfMonth				()
			n			daysOfYear				()

			n			dayOfWeek					()
			n			dayOfYear					()
			n			weekOfMonth				()
			n			weekOfYear				()

		Legend:

		fid				f|s+			format id or format inline string/function
		pattern		f|s+			format inline string or function f(d|s+, type) { .. }
		date			d
		units			s+
		timezone 	obj				{ abbreviation, offset, hours, minutes }

		Format rule:
			data format or data locale + public or sys locale  + puiblic

		units:	y, m, w, d, h, mn, s, ms

			example: -2y 3m -1h-3mn-1s-2ms
			example: ldw-2y3m1h3mn1s2ms
			example: 2years3months1hours3minutes1seconds2milliseconds

		format:

			days:
				DAY 		- uppercase full day name
				Day 		- mixedcase full day name
				day 		- lowercase full day name

				DY			- uppercase short day name
				Dy			- mixedcase short day name
				dy			- lowercase short day name

				dw			- day number in the week (1-7)
			 ddw			- day number in the week (1-7) with zero padding

				d				- day number in the month (1-31)
				dd			- day number in the month (1-31) with zero padding

			 dyy			- day number in the year (1-366)
			 ddy			- day number in the year (1-366) with zero padding

			 sf				- day suffix (1st, 2nd, 3rd, 4th, ..)

			weeks:
 				wm			- week number in the month (1-5)
			 wwm			- week number in the month (1-5)	with zero padding

				wy			- week 	number in the year (1-53)
			 wwy			- week 	number in the year (1-53) with zero padding

			months:
				MONTH		- uppercase full month name
				Month		- mixedcase full month name
				month		- lowercase full month name

				MT			- uppercase short month name
				Mt			- mixedcase short month name
				mt			- lowercase short month name

				 m			- month number in the year (1-12)
			  mm			- month number in the year (1-12) with zero padding

			years:
				 y			- last 2 digits of year
				yy			- last 2 digits of year with zero padding
			yyyy			- year 4 digits

			time:
				h				- hour of day(1-12)
				hh			- hour of day(1-12) with zero padding
			 	H				-	hour of day(0-23)
				HH			- hour of day(0-23) with zero padding
				mn			- minutes (0-59)
				mmn			- minutes (0-59) with zero padding
				s				- seconds (0-59)
				ss			- seconds (0-59) with zero padding
				ms			- milliseconds (0-999)
				mms			- milliseconds (0-999) with zero padding

				MR			- uppercase meridian indicator	(AM, PM)
				mr			- lowercase meridian indicator 	(am, pm)

		timezone:
				z				- UTC time zone offset 										ex: +0100
				zs			- UTC time zone offset short							ex: +01
				z:			- UTC time zone offset with : separator		ex: +01:00
				za			- UTC time zone abbreviation

		Note:
			All other mask symbol are treated as literal

	************************************************************************************************/

	//-------------------------------------------------------------------------------
  jsl.Date = function(date) {
  	try {
  		var proto, rv
			//!
	    if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(date, "d", "date")//!

			if(arguments.length)
				if(date.__augmented) 	return date
				else									rv = date
			else
				rv = new Date

			proto = jsl.Date.prototype
    	for(var id in proto) rv[id] = proto[id]
			return rv
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
  }
  //-------------------------------------------------------------------------------
	jsl.Date.__name 							= "jsl.Date"
  jsl.Date.__native							= { fromLString: true, now: true, format: true, __name: true, __augmented: true }
	jsl.Date.__augmented					= true
  //-------------------------------------------------------------------------------
	jsl.Date.prototype						= jsl.Object()
	jsl.Date.prototype.__name 		= "jsl.Date"
	jsl.Date.prototype.__native 	= jsl.Object.clone(jsl.Object.prototype.__native)
  //-------------------------------------------------------------------------------
	jsl.Date.__f				= "date"
	jsl.Date.__fs				= {

		date:						null,
		date_l:					null,
		time:						null,
		time_l:					null,
		month_day:			null,
		month_year:			null,

		//iso8601
		iso8601:				"yyyy-mm-dd",
    iso8601_l:			"yyyy-mm-dd hh:mmn:ssz",

		iso8601_time:		"HH:mmn",
		iso8601_time_l:	"HH:mmn:ss",

    iso8601_yd:			"yyyy-ddy",
    iso8601_ym:			"yyyy-mm",
    iso8601_yw:			"yyyy-Wwwy",
    iso8601_ywd:		"yyyy-Wwwy-dw"
	}
	//constants
  //-------------------------------------------------------------------------------
	jsl.Date.MILLISECOND 	= 1
	jsl.Date.SECOND 			= jsl.Date.MILLISECOND 	* 1000
	jsl.Date.MINUTE 			= jsl.Date.SECOND				* 60
	jsl.Date.HOUR				 	= jsl.Date.MINUTE				* 60
	jsl.Date.DAY 					= jsl.Date.HOUR					* 24
	jsl.Date.WEEK 				= jsl.Date.DAY					* 7

	//gregorian calendar with leaps year every 4 and -3 every 400 years
	//year average in days: 365.2425
	//we still use simple numbers to avoid that moving a date of n month move also h, m etc..
	jsl.Date.YEAR 				= jsl.Date.DAY					* 365 //365.2425
	jsl.Date.MONTH 				= jsl.Date.DAY					* 30	//30.436875

	//-------------------------------------------------------------------------------
	jsl.error("DateError", jsl.ParamError)
  //-------------------------------------------------------------------------------
	jsl.Date.fromLString = function(s, fid) {
		try {
			var l, fs, rv, fm, re, re2, li, ds, data, mtc, er
			var y, m, wy, wm, d, dw, dy, h, H, mn, sn, ms, mr, n, dt, f, sf, z, d1, m1, dt2, za

			//!
			if(!arguments.length || arguments.length > 3)	throw jsl.ParamError()
			jsl.validate(s, "s+", "s")
			if(arguments.length === 2)	jsl.validate(fid					, "t[f,s+]"	, "fid")
			if(arguments.length > 2)		jsl.validate(fid					, "s+"			, "locale")
			if(arguments.length > 2)		jsl.validate(arguments[2]	, "s+"			, "fid")//!

			//!
			er = jsl.ParamError()
			er.__date = true//!

			jsl.require("locale")
			l = jsl.Locale.get()

			//1-public formats
			if(!fid) {
				fs = jsl.Object.clone(this.__fs)
				jsl.Object.walk(fs, function(v, id) { if(!v) fs[id] = l.d_formats[id] })
			}

			//2-inline function format
			else if(jsl.isFunction(fid))	{
				try 			{ rv = fid(s + "") }
				catch(e) 	{ /*!*/throw (e instanceof jsl.DateError 	? jsl.ParamError("NotRecognized:s", e)
																														: jsl.ParamError("BadScript:fid", e))/*!*/ }

				//!
				if(!jsl.isDate(rv))	throw jsl.ParamError("BadReturnType:fid:Date")//!
				fs = {}
			}

			//3-inline format id
			else if(fid in this.__fs) {

				fm = this.__fs[fid]
				if(!fm) fm = l.d_formats[fid]
				fs = { fm: fm }
			}

			//4-inline locale
			else if(arguments.length === 3 || jsl.Locale.isDefined(fid)) {

				//!
				if(!jsl.Locale.isDefined(fid))	throw jsl.ParamError("NotDefined:locale(fid)")//!
				l	= jsl.Locale.get(fid)

				if(!arguments[2]) {
					fs = jsl.Object.clone(this.__fs)
					jsl.Object.walk(fs, function(v, id) { if(!v) fs[id] = l.d_formats[id] })
				}
				else if(l.d_formats[arguments[2]])	fs = { fm: l.d_formats[arguments[2]] }
				else																fs = { fm: arguments[2] }
			}
			//5-inline string format
			else
				fs = { fm: fid }

			re	= "(!*)(DAY|Day|dyy|day|DY|Dy|dy|MONTH|Month|month|MT|Mt|mt|MR|mr|hh|h|HH|H|mmn|mn|sf|ss|s|mms|ms|dw|ddw|" +
					 	"ddy|dd|d|wm|wwm|wy|wwy|mm|m|yyyy|yy|y|za|zs|z:|z|$)"

			re  = RegExp(re, "g")
			re2	= RegExp((re + "").slice(1, -2)) //-> -2 global flag
			f		= function(s, g1, g2){
				if(g1 && g1.length % 2) return g1.slice(0, ~~(g1.length / 2)) + g2
				else if(g1) 						return g1.slice(0, g1.length / 2) 		+ g2
				else 										return s
			}

			for(var id in fs)
				if(fs[id] != null) {

					fm = fs[id]

					if(jsl.isFunction(fm)) {

						try 			{ rv = fm(s + "")	}
						catch(e) 	{ continue 				}

						//!
						if(!jsl.isDate(rv))	throw jsl.ParamError("BadReturnType:locale[" + l.id + "\\:" + id + "]:Date")//!
						break;
					}

					re.lastIndex 	= 0
					li						= 0
					ds						= s + ""
					dw = d = dy 	= sf = wm = wy = m = y = mr = h = H = mn = sn = ms = z = za = null

					parsing:
					while((mtc = re.exec(fm))) {

						//no look-beahind re in js
						if(mtc[1])
							if(mtc[1].length % 2) mtc.index += mtc[0].length, mtc[2] = null
							else									mtc.index += mtc[1].length

						if(mtc.index > li) {

							data = ds.match("^" + fm.slice(li, mtc.index).replace(re2, f).replace(/[\^\$\.\*\+\?\=\!\:\|\\\/\(\)\[\]\{\}]/g, "\\$&"))

							if(!data) break;
							ds = ds.slice(data[0].length)
							if(!mtc[2]) {
								li = re.lastIndex
								continue
							}
						}

						data = null

						switch(mtc[2]) {

							//days
			 				//-------------------------------------------------------------------------------
							case "DAY":
							case "day":
							case "Day":

								data 	= l.d_days.join("|").toLowerCase()
								dt 		= ds.match(RegExp("^" + data, "i"))

								if(!dt) break parsing
								n 		= jsl.Array.index(data.split("|"), dt[0].toLowerCase())

								//!
								if(dw != null && dw !== n) throw er.message("date.InconsistentDate:s(dw)")//!
								if(dw != null && dw !== n) break parsing

								dw		= n
								data 	= dt
								break

							case "DY":
							case "dy":
							case "Dy":

								data 	= l.d_days_short.join("|").toLowerCase()
								dt 		= ds.match(RegExp("^" + data, "i"))

								if(!dt) break parsing
								n 		= jsl.Array.index(data.split("|"), dt[0].toLowerCase())

								//!
								if(dw != null && dw !== n) throw er.message("date.InconsistentDate:s(dw)")//!
								if(dw != null && dw !== n) break parsing

								dw		= n
								data 	= dt
								break

							case "dw":						data = ds.match(/^[1234567]/)
							case "ddw": if(!data)	data = ds.match(/^0[1234567]/)

								if(!data) 			break parsing
								n = +data[0] - 1
								n = (n + l.d_first_wday) % 7

								//!
								if(dw != null && dw !== n) throw er.message("date.InconsistentDate:s(dw)")//!
								if(dw != null && dw !== n) break parsing

								dw = n
								break

							case "d":							data = ds.match(/^\d{1,2}/)
							case "dd":	if(!data) data = ds.match(/^\d{2}/)

								if(!data) 		break parsing
								n	= +data[0]

								if(!(n >= 1 && n <= 31))
									break parsing

								//!
								if(d != null && d !== n) throw er.message("date.InconsistentDate:s(d)")//!
								if(d != null && d !== n) break parsing

								d = n
								break

							case "dyy":						data = ds.match(/^\d{1,3}/)
							case "ddy":	if(!data)	data = ds.match(/^\d{3}/)

								if(!data) 			break parsing
								n = +data[0]

								if(!(n >= 1 && n <= 366))
									break parsing

								//!
								if(dy != null && dy !== n) throw er.message("date.InconsistentDate:s(dy)")//!
								if(dy != null && dy !== n) break parsing

								dy = n
								break

							case "sf":

								data = ds.match(RegExp(l.d_days_ordinals.join("|"), "i"))
								if(!data) break parsing

								//!
								if(sf != null && sf !== data[0]) throw er.message("date.InconsistentDate:s(sf)")//!
								if(sf != null && sf !== data[0]) break parsing

								sf = data[0]
								break

							//weeks
			 				//-------------------------------------------------------------------------------
							case "wm":						data = ds.match(/^[12345]/)
							case "wwm":	if(!data)	data = ds.match(/^0[12345]/)

								if(!data) break parsing
								n = +data[0]

								//!
								if(wm != null && wm !== n) throw er.message("date.InconsistentDate:s(wm)")//!
								if(wm != null && wm !== n) break parsing
								wm = n
								break

							case "wy":						data = ds.match(/^\d{1,2}/)
							case "wwy":	if(!data)	data = ds.match(/^\d{2}/)

								if(!data) break parsing
								n = +data[0]

								if(!(n >= 1 && n <= 53))
									break parsing

								//!
								if(wy != null && wy !== n) throw er.message("date.InconsistentDate:s(wy)")//!
								if(wy != null && wy !== n) break parsing
								wy = n
								break

							//months
			 				//-------------------------------------------------------------------------------
							case "MONTH":
							case "month":
							case "Month":

								data 	= l.d_months.join("|").toLowerCase()
								dt 		= ds.match(RegExp("^" + data, "i"))
								if(!dt) break parsing
								n 		= jsl.Array.index(data.split("|"), dt[0].toLowerCase())

								//!
								if(m != null && m !== n) throw er.message("date.InconsistentDate:s(m)")//!
								if(m != null && m !== n) break parsing

								m			= n
								data 	= dt
								break

							case "MT":
							case "mt":
							case "Mt":

								data 	= l.d_months_short.join("|").toLowerCase()
								dt 		= ds.match(RegExp("^" + data, "i"))

								if(!dt) break parsing
								n 		= jsl.Array.index(data.split("|"), dt[0].toLowerCase())

								//!
								if(m != null && m !== n) throw er.message("date.InconsistentDate:s(m)")//!
								if(m != null && m !== n) break parsing

								m			= n
								data 	= dt
								break

							case "m":							data = ds.match(/^\d{1,2}/)
							case "mm":	if(!data)	data = ds.match(/^\d{2}/)

								if(!data) 		break parsing
								n	= +data[0] - 1

								if(!(n >= 0 && n <= 11))
									break parsing

								//!
								if(m != null && m !== n) throw er.message("date.InconsistentDate:s(m)")//!
								if(m != null && m !== n) break parsing

								m	= n
								break

							//years
			 				//-------------------------------------------------------------------------------
							case "yyyy": 						data = ds.match(/^\d{4}/)
							case "yy":		if(!data) data = ds.match(/^\d{2}/)
							case "y":			if(!data) data = ds.match(/^\d{1,2}/)

								if(!data) 		break parsing
								n = data[0]

								if(n.length === 1)			n = ((new Date).getFullYear() + "").slice(0, -2) + "0" + n
								else if(n.length === 2)	n = ((new Date).getFullYear() + "").slice(0, -2) + n

								n	= +n

								//!
								if(y != null && y !== n) throw er.message("date.InconsistentDate:s(y)")//!
								if(y != null && y !== n) break parsing
								y	= n
								break

							//time
			 				//-------------------------------------------------------------------------------
							case "MR":
							case "mr":

								data = ds.match(RegExp("^" + l.d_am + "|" + l.d_pm, "i"))
								if(!data) break parsing

								n = data[0].toLowerCase() === l.d_am.toLowerCase() ? 1 : 2

								//!
								if(mr != null && mr !== n) throw er.message("date.InconsistentDate:s(mr)")//!
								if(mr != null && mr !== n) break parsing
								mr = n
								break

							case "h":							data = ds.match(/^\d{1,2}/)
							case "hh":	if(!data)	data = ds.match(/^\d{2}/)

								if(!data) break parsing
								n	= +data[0]

								if(!(n >= 1 && n <= 12))
									break parsing

								//!
								if(h != null && h !== n) throw er.message("date.InconsistentDate:s(h)")//!
								if(h != null && h !== n) break parsing
								h = n
								break

							case "H":							data = ds.match(/^\d{1,2}/)
							case "HH":	if(!data)	data = ds.match(/^\d{2}/)

								if(!data) break parsing
								n	= +data[0]

								if(!(n >= 0 && n <= 23))
									break parsing

								//!
								if(H != null && H !== n) throw er.message("date.InconsistentDate:s(h)")//!
								if(H != null && H !== n) break parsing
								H = n
								break

							case "mn":						data = ds.match(/^\d{1,2}/)
							case "mmn":	if(!data)	data = ds.match(/^\d{2}/)

								if(!data) break parsing
								n = +data[0]

								if(!(n >= 0 && n <= 59))
									break parsing

								//!
								if(mn != null && mn !== n) throw er.message("date.InconsistentDate:s(mn)")//!
								if(mn != null && mn !== n) break parsing
								mn = n
								break

							case "s":							data = ds.match(/^\d{1,2}/)
							case "ss":	if(!data)	data = ds.match(/^\d{2}/)

								if(!data) 			break parsing
								n = +data[0]

								if(!(n >= 0 && n <= 59))
									break parsing

								//!
								if(sn != null && sn !== n) throw er.message("date.InconsistentDate:s(sn)")//!
								if(sn != null && sn !== n) break parsing
								sn = n
								break

							case "ms":						data = ds.match(/^\d{1,3}/)
							case "mms":	if(!data)	data = ds.match(/^\d{3}/)

								if(!data) 			break parsing
								n = +data[0]

								if(!(n >= 0 && n <= 999))
									break parsing

								//!
								if(ms != null && ms !== n) throw er.message("date.InconsistentDate:s(ms)")//!
								if(ms != null && ms !== n) break parsing
								ms = n
								break

							case "z":
								data = ds.match(/^(\+|\-)\d{4}/)
								if(!data) break parsing

								//!
								if(z != null && z !== data[0]) throw er.message("date.InconsistentDate:s(z)")//!
								if(z != null && z !== data[0]) break parsing
								z	= data[0]
								break

							case "zs":
								data = ds.match(/^(\+|\-)\d{2}/)
								if(!data) break parsing

								//!
								if(z != null && z !== data[0] + "00")	throw er.message("date.InconsistentDate:s(z)")//!
								if(z != null && z !== data[0] + "00")	break parsing
								z	= data[0] + "00"
								break

							case "z:":
								data = ds.match(/^(\+|\-)\d{2}:\d{2}/)
								if(!data) break parsing

								//!
								if(z != null && z !== data[0].replace(":", ""))	throw er.message("date.InconsistentDate:s(z)")//!
								if(z != null && z !== data[0].replace(":", ""))	break parsing
								z	= data[0]
								break

							case "za":
								data = ds.match(/^\w+/)
								if(!data) break parsing

								//!
								if(za != null && za !== data[0]) throw er.message("date.InconsistentDate:s(za)")//!
								if(za != null && za !== data[0]) break parsing
								za	= data[0]
								break

							default:
								//when is matched the end of the string
								break parsing
						}

						ds = ds.slice(data[0].length)
						li = re.lastIndex
					}

					//data string completly consumed
					if(!ds) {

						dt = new Date

						if(H != null)										h = H
						else if(h != null && mr === 1) 	h	= h === 12 ? 0 : h
						else if(h != null && mr === 2) 	h	= h === 12 ? h : h + 12
						else														h = null

						if(dw != null && wy != null) {

							//iso8601
							n 	= (new Date(y || dt.getFullYear(), 0, 1)).getDay() - l.d_first_wday
							wy	= n <= 3 ? wy - 1 : wy
							dt2	= new Date(y || dt.getFullYear(), 0, ((wy - 1) * jsl.Date.WEEK) / jsl.Date.DAY + dw + 7 - n)

							d1 	= dt2.getDate()
							m1 	= dt2.getMonth()

							//!
							if(d != null && d !== d1)	throw er.message("date.InconsistentDate:s(d)")
							if(m != null && m !== m1)	throw er.message("date.InconsistentDate:s(m)")//!

							if(d != null && d !== d1 || m != null && m !== m1)
								break;

							d = d1
							m = m1
						}

						if(dy != null) {
							data 	= new Date(y || dt.getFullYear(), 0, dy)

							//!
							if(d != null && d !== data.getDate())		throw er.message("date.InconsistentDate:s(d)")
							if(m != null && m !== data.getMonth())	throw er.message("date.InconsistentDate:s(d)")//!

							if(d != null && d !== data.getDate() || m != null && m !== data.getMonth())
								break;

							d = data.getDate()
							m = data.getMonth()
						}

						if(dw != null && wm != null) {
							d1 = (wm - 1) * 7 + dw + 1 + 7 - (new Date(y || dt.getFullYear(), m != null ? m : dt.getMonth())).getDay()

							//!
							if(d != null && d !== d1)	throw er.message("date.InconsistentDate:s(d)")//!
							if(d != null && d !== d1) break;
							d = d1
						}

						rv = new Date(
														y 	!= null ? y 	: dt.getFullYear(),
														m 	!= null ? m 	: dt.getMonth(),
														d 	!= null ? d 	: dt.getDate(),
														h 	!= null ? h 	: dt.getHours(),
														mn 	!= null ? mn 	: dt.getMinutes(),
														sn	!= null ? sn	: dt.getSeconds(),
														ms	!= null ? ms 	: dt.getMilliseconds())

						//!
						if(d != null 	&& d !== rv.getDate())				throw er.message("date.InconsistentDate:s(d)")
						if(m != null	&& m 	!== rv.getMonth())			throw er.message("date.InconsistentDate:s(d)")

						if(dy === 366 && !jsl.Date.isLeapYear(rv))	throw er.message("date.InconsistentDate:s(dy)")
						if(dw != null	&& dw !== rv.getDay())				throw er.message("date.InconsistentDate:s(dw)")//!

						if( (d != null 	&& d !== rv.getDate()) 				||
								(m != null	&& m 	!== rv.getMonth())			||
								(dy === 366 && !jsl.Date.isLeapYear(rv))	||
								(dw != null	&& dw !== rv.getDay()))
									rv = undefined

						break
					}
				}

			//!
			if(!rv)	throw er.message("NotRecognized:s")//!
			return rv
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.now = function() {
		try {//!
			if(arguments.length)	throw jsl.ParamError()//!
			return new Date
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.format = function(fid, pattern) {
		try {
			var v, l//!
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(fid, "s+", "fid")//!

			if(arguments.length === 2) {//!
				if(pattern != null) jsl.validate(pattern, "t[f,s+]"	, "pattern")//!
				this.__fs[fid] = typeof pattern !== "function" ? pattern + "" : pattern
				v = this
			}
			else {
				v = this.__fs[fid]
				if(!v) {
					l = jsl.Locale.get()
					v = l.d_formats[fid]
				}

				//!
				if(!v)	throw jsl.ParamError("NotDefined", [fid])//!
			}

			return v
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.date = function(date) {
		try {
			var v//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()//!

			if(arguments.length) {//!
				jsl.validate(date, "i[1,31]", "date")//!
				this.setDate(date)
				v = this
			}
			else
				v = this.getDate()

			return v
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.month = function(month) {
		try {
			var v//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()//!

			if(arguments.length) {//!
				jsl.validate(month, "i[0,11]", "month")//!
				this.setMonth(month)
				v = this
			}
			else
				v = this.getMonth()

			return v
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.year = function(year) {
		try {
			var v//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()//!

			if(arguments.length) {//!
				jsl.validate(year, "i++", "year")
				if(year < 1000)	throw jsl.ParamError("BadValue:year")//!

				this.setFullYear(year)
				v = this
			}
			else
				v = this.getFullYear()

			return v
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.hours = function(hours) {
		try {
			var v//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()//!

			if(arguments.length) {//!
				jsl.validate(hours, "i[0,23]", "hours")//!

				this.setHours(hours)
				v = this
			}
			else
				v = this.getHours()

			return v
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.minutes = function(minutes) {
		try {
			var v//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()//!

			if(arguments.length) {//!
				jsl.validate(minutes, "i[0,59]", "minutes")//!

				this.setMinutes(minutes)
				v = this
			}
			else
				v = this.getMinutes()

			return v
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.seconds = function(seconds) {
		try {
			var v//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()//!

			if(arguments.length) {//!
				jsl.validate(seconds, "i[0,59]", "seconds")//!

				this.setSeconds(seconds)
				v = this
			}
			else
				v = this.getSeconds()

			return v
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.milliseconds = function(milliseconds) {
		try {
			var v//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()//!

			if(arguments.length) {//!
				jsl.validate(milliseconds, "i[0,999]", "milliseconds")//!

				this.setMilliseconds(milliseconds)
				v = this
			}
			else
				v = this.getMilliseconds()

			return v
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.isDate = function(s, fid) {
		try {
			var b

			try 			{ b = jsl.Date.fromLString.apply(this, arguments)	}
			catch(e) 	{ /*!*/	if(e.__date) b = false
												else throw e.clearStackTrace()/*!*/}

			return !!b
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.locale = function(id) {
		try {
			var v//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()//!

			if(arguments.length) {//!
				if(id != null) jsl.validate(id, "s+", "id")//!

				if(this.__l != id)  {

					jsl.require("locale")//!
					if(id != null && !jsl.Locale.isDefined(id))	throw jsl.ParamError("NotDefined:id")//!

					//force the normalization of the id
					this.__l = id ? jsl.Locale.get(id).id : jsl.Locale.current()
				}

				v = this
			}
			else {
				if(!this.__l) {
					jsl.require("locale")
					this.__l = jsl.Locale.current()
				}

				v = this.__l
			}

			return v
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.format = function(fid) {
		try {
			var v//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()//!

			if(arguments.length) {//!
				if(fid != null) jsl.validate(fid, "t[f,s+]", "fid")//!

				if(fid != this.__f)
					if(fid == null)	this.__f = null
					else						this.__f = jsl.isFunction(fid) ? fid : fid + ""

				v = this
			}
			else
				v = this.__f || null

			return v
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.toLString = function(fid) {
		try {
			var fm, rv, re, l, d

			//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(fid, "t[f,s+]", "fid")//!

			l = jsl.Date.locale(this)
			l = jsl.Locale.get(l)

			//1-default custom format
			if(!fid && this.__f)
				if(jsl.isFunction(this.__f))				fm = this.__f
				else if(this.__f in jsl.Date.__fs)	fm = jsl.Date.__fs[this.__f] || l.d_formats[this.__f]
				else																fm = this.__f

			//2-default locale format
			else if(!fid && !this.__f)
				fm = l.d_formats.date

			//3-inline function format
			else if(jsl.isFunction(fid))	{
				try 			{ rv = fid(new Date(+this))	}
				catch(e) 	{ throw jsl.ParamError("BadScript:fid", e) }

				//!
				if(!jsl.isString(rv))	throw jsl.ParamError("BadReturnValue:fid:string")//!
				rv += ""
			}

			//4-inline format id
			else if(fid in jsl.Date.__fs) {

				fm = jsl.Date.__fs[fid]
				if(!fm) fm = l.d_formats[fid]
			}

			//5-inline locale
			else if(jsl.Locale.isDefined(fid))
				fm = jsl.Locale.get(fid).d_formats.date

			//6-inline string format
			else
				fm = fid

			if(rv == null)
			if(jsl.isFunction(fm)) {
				try 			{ rv = fm(+this) }
				catch(e) 	{ throw jsl.ParamError("BadScript:fid", e) }

				//!
				if(!jsl.isString(rv))	throw jsl.ParamError("BadReturnType:fid:string")//!
				rv += ""
			}

			else {
				re = 	"(!*)(DAY|Day|day|dyy|DY|Dy|dy|MONTH|Month|month|MT|Mt|mt|MR|mr|hh|h|HH|H|mmn|mn|sf|ss|s|mms|ms|dw|ddw|" +
							"ddy|dd|d|wm|wwm|wy|wwy|mm|m|yyyy|yy|y|za|zs|z:|z)"

				re 	= RegExp(re, "g")
				d		= this

				rv 	= fm.replace(re, function(m, g1, g2) {
					var v

					if(g1 && g1.length % 2)
						return g1.slice(0, ~~(g1.length / 2)) + g2

					switch(g2) {

						case "DAY":		v = l.d_days[d.getDay()].toUpperCase();														break
						case "day":		v = l.d_days[d.getDay()].toLowerCase();														break
						case "Day":		v = l.d_days[d.getDay()]
													v = v.charAt(0).toUpperCase() + v.slice(1).toLowerCase();					break

						case "DY":		v = l.d_days_short[d.getDay()].toUpperCase();											break
						case "dy":		v = l.d_days_short[d.getDay()].toLowerCase();											break
						case "Dy":		v = l.d_days_short[d.getDay()]
													v = v.charAt(0).toUpperCase() + v.slice(1).toLowerCase();					break

						case "dw": 		v = jsl.Date.dayOfWeek(this);																			break
						case "ddw": 	v = "0" + jsl.Date.dayOfWeek(this);																break

						case "d": 		v = d.getDate();																									break
						case "dd": 		v = jsl.String.padLeft(d.getDate() + "", 2, "0");									break

						case "dyy": 	v = jsl.Date.dayOfYear(this);																			break
						case "ddy": 	v = jsl.String.padLeft(jsl.Date.dayOfYear(this) + "", 3, "0");		break

						case "sf":		v = l.d_days_ordinals[this.getDate()] || l.d_days_ordinals[0];		break

						//-------------------------------------------------------------------------------
						case "wm": 		v = jsl.Date.weekOfMonth(this);																		break
						case "wwm": 	v = jsl.String.padLeft(jsl.Date.weekOfMonth(this) + "", 2,"0");		break

						case "wy": 		v = jsl.Date.weekOfYear(this);																		break
						case "wwy": 	v = jsl.String.padLeft(jsl.Date.weekOfYear(this) + "", 2, "0");		break

						//-------------------------------------------------------------------------------
						case "MONTH": v = l.d_months[d.getMonth()].toUpperCase(); 											break
						case "month": v = l.d_months[d.getMonth()].toLowerCase(); 											break
						case "Month": v = l.d_months[d.getMonth()]
													v = v.charAt(0).toUpperCase() + v.slice(1).toLowerCase();					break

						case "MT": 		v = l.d_months_short[d.getMonth()].toUpperCase(); 								break
						case "mt": 		v = l.d_months_short[d.getMonth()].toLowerCase(); 								break
						case "Mt": 		v = l.d_months_short[d.getMonth()]
													v = v.charAt(0).toUpperCase() + v.slice(1).toLowerCase(); 				break

						case "m": 		v = d.getMonth() + 1;																							break
						case "mm": 		v = jsl.String.padLeft(d.getMonth() + 1 + "", 2, "0");						break

						//-------------------------------------------------------------------------------
						case "y": 		v = +(d.getFullYear() + "").slice(2) + "";												break
						case "yy": 		v = (d.getFullYear()	+ "").slice(2);															break
						case "yyyy": 	v = d.getFullYear()	+ "";																					break

						//-------------------------------------------------------------------------------
						case "MR": 		v = l[d.getHours() >= 12 ? "pm" : "am" ].toUpperCase();		 				break
						case "mr": 		v = l[d.getHours() >= 12 ? "pm" : "am" ]; 												break

						case "h": 		v = d.getHours() % 12 || 12;																			break
						case "hh": 		v = jsl.String.padLeft((d.getHours() % 12 || 12) + "", 2, "0");		break
						case "H": 		v = d.getHours();																									break
						case "HH": 		v = jsl.String.padLeft(d.getHours() + "", 2, "0");								break

						case "mn": 		v = d.getMinutes();																								break
						case "mmn": 	v = jsl.String.padLeft(d.getMinutes() + "", 2, "0");							break

						case "s": 		v = d.getSeconds();																								break
						case "ss": 		v = jsl.String.padLeft(d.getSeconds() + "", 2, "0");							break

						case "ms": 		v = d.getMilliseconds();																					break
						case "mms": 	v = jsl.String.padLeft(d.getMilliseconds() + "", 3, "0");					break

						//-------------------------------------------------------------------------------
						case "z": 		v = jsl.Date.timeZone(d).offsetS.replace(":", "");								break
						case "zs": 		v = jsl.Date.timeZone(d).offsetS.slice(0, 3);											break
						case "z:": 		v = jsl.Date.timeZone(d).offsetS;																	break
						case "za": 		v = jsl.Date.timeZone(d).abbreviation;														break
					}

					return (g1 ? g1.slice(0, g1.length / 2) : "") + v
				})
			}

			return rv
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.useDst = function() {
		try {
			var cy, d1, d2

			//!
			if(!jsl.isDate(this))	throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length)	throw jsl.ParamError()//!

			cy = this.getFullYear()
			d1 = new Date(cy, 0, 1)
			d2 = new Date(cy, 5, 1)

			return d1.getTimezoneOffset() !== d2.getTimezoneOffset()
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.isInDst = function() {
		try {
			var cy, d1, d2, d3, dn, t1, t2, t3, b

			//!
			if(!jsl.isDate(this))	throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length)	throw jsl.ParamError()//!

			cy = this.getFullYear()
			d1 = new Date(cy, 0, 1)
			d2 = new Date(cy, 5, 1)
			d3 = this

			t1 = d1.getTimezoneOffset()
			t2 = d2.getTimezoneOffset()
			t3 = d3.getTimezoneOffset()
			dn = t1 - t2

			if(dn > 0)			b = t3 === t2
			else if(dn < 0)	b = t3 === t1
			else						b = false

			return b
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.dstStart = function() {
		try {
			var d1, d2, y, d, hsp, ld1, h

			//!
			if(!jsl.isDate(this))				throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length)				throw jsl.ParamError()
			if(!jsl.Date.useDst(this))	throw jsl.MisuseError("date.DstNotUsed")//!

			y		= this.getFullYear()
			d1 	= new Date(y, 0, 1)
			d2 	= new Date(y, 5, 1)
			hsp	= d1.getTimezoneOffset() - d2.getTimezoneOffset()
			h		= jsl.Date.HOUR

			if(hsp < 0)	{
				d 	= d1
				d1	= d2
				d2 	= d
				d2.setDate(31, 11)
			}

			while(d2 - d1 > h) {

				if(d2.getTimezoneOffset() === d1.getTimezoneOffset())	{
					d2 = d1
					d1 = ld1
				}
				else {
					ld1 = new Date(+d1)
					d1.setMilliseconds(Math.round((d2 - d1) / 2))
				}
			}

			return d2
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.dstEnd = function() {
		try {
			var d1, d2, y, d, hsp, ld1, h

			//!
			if(!jsl.isDate(this))				throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length)				throw jsl.ParamError()
			if(!jsl.Date.useDst(this))	throw jsl.MisuseError("date.DstNotUsed")//!

			y		= this.getFullYear()
			d1 	= new Date(y, 5	, 1)
			d2 	= new Date(y, 11, 31)
			hsp	= d2.getTimezoneOffset() - d1.getTimezoneOffset()
			h		= jsl.Date.HOUR

			if(hsp < 0)	{
				d 	= d1
				d1	= d2
				d2 	= d
				d2.setFullYear(y + 1)
			}

			while(d2 - d1 > h) {

				if(d2.getTimezoneOffset() === d1.getTimezoneOffset())	{
					d2 = d1
					d1 = ld1
				}
				else {
					ld1 = new Date(+d1)
					d1.setMilliseconds(Math.round((d2 - d1) / 2))
				}
			}

			d1.setHours(d1.getHours() - 1)
			return d1
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.timeZone = function(dst) {
		try {
			var tzs, isInDst, dstz, tzo, ds, h, m, jslS

			//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(dst, "b", "dst")//!

			jsl.require("locale")

			tzs			=	jsl.Locale.get().d_tzs
			isInDst	=	jsl.Date.isInDst(this)
			dstz 		= dst == null ? isInDst : dst
			//@sys: Opera 10.50 -this.getTimezoneOffset() can return bad results as 119.99998333333333
			//			instead of 60
			tzo			= Math.round(-this.getTimezoneOffset())
			tzo			= isInDst 	? tzo - 60 	: tzo
			ds			= (tzs[tzo] || "?:?").split(":")
			tzo			= dstz ? tzo + 60 : tzo

			//!
			if(dst && !ds[1])	throw jsl.ParamError("BadValue:dst")//!

			h 		= ~~(tzo / 60)
			m 		= Math.abs(tzo % 60)
			jslS	= jsl.String

			return {
								abbreviation: dstz ? ds[1] : ds[0],
								offset:  (h > 0 ? "+" : "-") + jslS.padLeft(h + "", 2, "0") + ":" + jslS.padLeft(m + "", 2, "0"),
								hours: 	 h,
								minutes: m
						 }
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.move = function(units, clone) {
		try {
			var n, u, re, d, i, map, jsld, rv

			//!
			if(!jsl.isDate(this))													throw jsl.TypeError("BadMethodCall:Date")
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(units, "t[i,s+]", "units")
			if(arguments.length === 2)	jsl.validate(clone, "b", "clone")//!

			n 		=	0
			u 		= jsl.isString(units) ? units : units + "d"
			re		= /((?:\+|\-)?\d+)(mn|ms|[ymwdhs])/gi
			jsld	= jsl.Date
			map		= { y: jsld.YEAR, m: 	jsld.MONTH	, w: jsld.WEEK	, d: 	jsld.DAY,
								h: jsld.HOUR, mn: jsld.MINUTE	, s: jsld.SECOND, ms: jsld.MILLISECOND }

			//the same problem of some browser versions
			re.lastIndex = 0
			do {

				i = re.lastIndex
				d	= re.exec(u)
				//!
				if(d == null || d.index !== i)	throw jsl.ParamError("BadSyntax:units")//!

				n += d[1] * map[d[2]]
			} while(i + d[0].length < units.length)

			rv = clone && clone.valueOf() ? new Date(this) : this
		 	rv.setMilliseconds(this.getMilliseconds() + n)

			return rv
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.toFirstDayOfWeek = function(clone) {
		try {
			var i, l, rv

			//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(clone, "b", "clone")//!

			l = jsl.Date.locale(this)
			i	= jsl.Locale.get(l).d_first_wday

			rv = clone && clone.valueOf() ? new Date(this) : this
			rv.setMilliseconds(this.getMilliseconds() - (this.getDay() - i) * jsl.Date.DAY)
			return rv
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.toLastDayOfWeek = function(clone) {
		try {
			var i, l, rv

			//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(clone, "b", "clone")//!

			l = jsl.Date.locale(this)
			i	= jsl.Locale.get(l).d_first_wday

			rv = clone && clone.valueOf() ? new Date(this) : this
			rv.setMilliseconds(this.getMilliseconds() + (6 - this.getDay() + i) * jsl.Date.DAY)
			return rv
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.toFirstDayOfMonth = function(clone) {
		try {
			var rv
			//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(clone, "b", "clone")//!

			rv = clone && clone.valueOf() ? new Date(this) : this
			rv.setDate(1)
			return rv
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.toLastDayOfMonth = function(clone) {
		try {
			var rv
			//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(clone, "b", "clone")//!

			rv = clone && clone.valueOf() ? new Date(this) : this
			rv.setDate(jsl.Date.daysOfMonth(this))
			return rv
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.toFirstDayOfYear = function(clone) {
		try {
			var rv
			//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(clone, "b", "clone")//!

			rv = clone && clone.valueOf() ? new Date(this) : this
			rv.setMonth(0, 1)
			return rv
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.toLastDayOfYear = function(clone) {
		try {
			var rv
			//!
			if(!jsl.isDate(this))			throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length > 1)	throw jsl.ParamError()
			if(arguments.length)			jsl.validate(clone, "b", "clone")//!

			rv = clone && clone.valueOf() ? new Date(this) : this
			rv.setMonth(11, 31)
			return rv
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.isInLeapYear = function() {
		try {
			var y, f, l, ly

			//!
			if(!jsl.isDate(this))	throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length)	throw jsl.ParamError()//!

			y = this.getFullYear() + ""
			f	= +y.slice(0, 2)
			l = +y.slice(2)

			if(l === "00")	ly = !(f / 4)
			else						ly = !(l % 4)

			return ly
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.between = function(date1, date2) {
		try {
			//!
			if(!jsl.isDate(this))				throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length !== 2)	throw jsl.ParamError()
			jsl.validate(date1, "d", "date1")
			jsl.validate(date2, "d", "date2")//!

			return date1 <= this && this <= date2
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.distance = function(date, unit) {
		try {
			var u, n, dms, d

			//!
			if(!jsl.isDate(this))													throw jsl.TypeError("BadMethodCall:Date")
			if(!arguments.length || arguments.length > 2)	throw jsl.ParamError()
			jsl.validate(date	, "d"	, "date")
			if(arguments.length === 2)	jsl.validate(unit, "s+", "unit")//!

			u 	= unit ? unit.toLowerCase() : "d"
			d		= jsl.Date
			dms	= Math.abs(this - date)

			if			(u === "y")		n = dms	/ d.YEAR
			else if	(u === "m")		n = dms / d.MONTH
			else if	(u === "w")		n = dms / d.WEEK
			else if	(u === "d")		n	= dms / d.DAY
			else if	(u === "h")		n = dms / d.HOUR
			else if	(u === "mn")	n = dms / d.MINUTE
			else if	(u === "s")		n = dms / d.SECOND
			else if	(u === "ms")	n = dms
			//!
			else throw jsl.ParamError("BadValue:unit")//!

			return n
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.daysOfMonth = function() {
		try {
			var ds, i
			//!
			if(!jsl.isDate(this))	throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length)	throw jsl.ParamError()//!

			ds 	= [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
			i		= this.getMonth()

			return i == 1 && jsl.Date.isInLeapYear(this) ? 29 : ds[i]
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.daysOfYear = function() {
		try {
			//!
			if(!jsl.isDate(this))	throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length)	throw jsl.ParamError()//!
			return jsl.Date.isInLeapYear(this) ? 366 : 365
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.dayOfWeek = function() {
		try {
			var l, d, i
			//!
			if(!jsl.isDate(this))	throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length)	throw jsl.ParamError()//!

			l = jsl.Date.locale(this)
			l	= jsl.Locale.get(l)
			i = l.d_first_wday
			d = this.getDay()

			return d >= i ? d - i + 1 : 8 - i + d
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.dayOfYear = function() {
		try {
			//!
			if(!jsl.isDate(this))	throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length)	throw jsl.ParamError()//!

			return Math.floor((this - new Date(this.getFullYear(), 0, 1) + jsl.Date.DAY) / jsl.Date.DAY)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.weekOfMonth = function() {
		try {
			//!
			if(!jsl.isDate(this))	throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length)	throw jsl.ParamError()//!

			return Math.ceil((this.getDate() * jsl.Date.DAY) / jsl.Date.WEEK)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
  //-------------------------------------------------------------------------------
	jsl.Date.prototype.weekOfYear = function() {
		try {
			var n, d

			//!
			if(!jsl.isDate(this))	throw jsl.TypeError("BadMethodCall:Date")
			if(arguments.length)	throw jsl.ParamError()//!

			n = (new Date(this.getFullYear(), 0, 1)).getDay()
			d	=  new Date(this.getFullYear(), 0, 7 - n)

			return Math.ceil((this - d) / jsl.Date.WEEK) + (n <= 3 ? 1 : 0)
		}
		catch(e) {
			jsl.throwError(e, this, arguments)
		}
	}
	//Date init
	//-------------------------------------------------------------------------------
	;(function() {
		var prt, Dte

		Dte = jsl.Date
		prt	= Dte.prototype

		for(var id in prt) {

			Dte.__native[id] = true
			prt.__native[id] = true

			if(typeof prt[id] === "function" && !prt[id].__name && id !== "format") {

				Dte[id] = function(obj) {
					try {
						//!
						if(!arguments.length)	throw jsl.ParamError()
						if(obj == null)				throw jsl.ParamError("NullValue:obj")//!

						return arguments.callee.__f.apply(obj, Array.prototype.slice.call(arguments, 1))
					}
					catch(e) {
						jsl.throwError(e, this, arguments)
					}
				}

				Dte[id].__name	= prt[id].__name = id
				Dte[id].__f			= prt[id]
			}
		}
	})()
